package ru.alperez.blurringtest;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.support.v8.renderscript.Allocation;
import android.support.v8.renderscript.RenderScript;
import android.support.v8.renderscript.ScriptIntrinsicBlur;
import android.util.TimingLogger;


public class Blurrer {
	private static final String TAG = "Blurring";
	
	private static Blurrer instance;
	
	public static Blurrer getInstance(Context ctx) {
		if (instance == null) {
			instance = new Blurrer(ctx);
		}
		return instance;
	}
	
	private RenderScript mRendScript;
	
	
	private Blurrer(Context ctx) {
		mRendScript = RenderScript.create(ctx.getApplicationContext());
	}
	
	public Bitmap blurImage(Context ctx, Bitmap srcImage, Bitmap dstImage, Rect window, int[] radius, int downScale, boolean useRenderScript) {
		
		if (dstImage != null && ((dstImage.getWidth() != srcImage.getWidth()) || (dstImage.getHeight() != srcImage.getHeight()))) {
			throw new IllegalArgumentException("If dstImage not null, it must be the same resolution as srcImage");
		}
		
		if (useRenderScript) {
			return blurImageRenderscript(ctx, srcImage, dstImage, window, radius, downScale);
		} else {
			return blurImageJava(ctx, srcImage, dstImage, window, radius, downScale);
		}
	}
	
	private Bitmap blurImageRenderscript(Context ctx, Bitmap srcImage, Bitmap dstImage, Rect wnd, int[] radius, int downScale) {
		
		Rect srcBounds = new Rect(0, 0, srcImage.getWidth(), srcImage.getHeight());
		if ((wnd.left >= wnd.right) || (wnd.top >= wnd.bottom)) {
			throw new IllegalArgumentException("Bad window dimentions: "+wnd.toString());
		}
		if (!srcBounds.contains(wnd)) {
			throw new IllegalArgumentException("Window must be insie image: window="+wnd.toShortString() + ", image="+srcBounds.toShortString());
		}
		if (downScale < 1) {
			throw new IllegalArgumentException("downscazlefactor must ne higher or equal 1. current value = "+downScale);
		}
		TimingLogger tLogger = new TimingLogger(TAG, "blurRS. downscale="+(downScale > 1));
		
		
		int realScale = Math.min(downScale, 8);
		Bitmap subImage = null;
		if (realScale == 1) {
			subImage = Bitmap.createBitmap(wnd.width(), wnd.height(), Bitmap.Config.ARGB_8888);
		} else {
			subImage = Bitmap.createBitmap((int)Math.ceil((double)(wnd.width()) / realScale), (int)Math.ceil((double)(wnd.height()) / realScale), Bitmap.Config.ARGB_8888);
		}
		tLogger.addSplit("create subimage");
		
		Canvas canv = new Canvas(subImage);
		canv.drawBitmap(srcImage, wnd, new Rect(0, 0, subImage.getWidth(), subImage.getHeight()), null);
		tLogger.addSplit("copy to subimage");
		
		Allocation overlayAlloc = Allocation.createFromBitmap(mRendScript, subImage);
	    ScriptIntrinsicBlur blur = ScriptIntrinsicBlur.create(mRendScript, overlayAlloc.getElement());
		for (int r : radius) {
			int realRadius = Math.min(r, 25);
			if (realRadius > 1) {
				realRadius = (int)Math.round(Math.ceil((double)realRadius / realScale));
			}
			
			blur.setInput(overlayAlloc);
			 
		    blur.setRadius(realRadius);
		 
		    blur.forEach(overlayAlloc);
		}
		
	    overlayAlloc.copyTo(subImage);
	    tLogger.addSplit("blurring time");
	    
	    //--- Create new bitmap to return ---
	    Bitmap ret = (dstImage != null) ? dstImage : Bitmap.createBitmap(srcBounds.width(), srcBounds.height(), Bitmap.Config.ARGB_8888);
	    canv = new Canvas(ret);
	    tLogger.addSplit("create empty result image");
	    
	    //--- Copy unchanged parts of the image if the output is new image ---
	    if (dstImage == null || ((dstImage != null) && (dstImage != srcImage))) {
	    	Rect partRect = null;
		    if (wnd.top > 0) { // Top part
		    	partRect = new Rect(0, 0, srcBounds.right, wnd.top);
		    	canv.drawBitmap(srcImage, partRect, partRect, null);
		    }
		    if (wnd.bottom < srcBounds.bottom) { // Bottom part
		    	partRect = new Rect(0, wnd.bottom, srcBounds.right, srcBounds.bottom);
		    	canv.drawBitmap(srcImage, partRect, partRect, null);
		    }
		    if (wnd.left > 0) { // Left part
		    	partRect = new Rect(0, wnd.top, wnd.left+1, wnd.bottom);
		    	canv.drawBitmap(srcImage, partRect, partRect, null);
		    }
		    if (wnd.right < srcBounds.right) { //Right part
		    	partRect = new Rect(wnd.right, wnd.top, srcBounds.right, wnd.bottom);
		    	canv.drawBitmap(srcImage, partRect, partRect, null);
		    }
		    tLogger.addSplit("copy not affected pixels to result");
	    }
	    
	    //--- Draw blurred image ---
		canv.drawBitmap(subImage, new Rect(0, 0, subImage.getWidth(), subImage.getHeight()), wnd, null);
		tLogger.addSplit("copy blurred part to result");
		tLogger.dumpToLog();
		
		return ret;
	}
	
	
	
	
	private Bitmap blurImageJava(Context ctx, Bitmap srcImage, Bitmap dstImage, Rect window, int[] radius, int downScale) {
		return null;
	}
}
